/* 
 * File:   TuringM.cpp
 * Author: miroslav
 * 
 * Created on December 27, 2010, 1:58 AM
 */

#include <stdlib.h>
#include <stdio.h>

#include <string>
#include <iostream>
#include <fstream>

#include "TuringM.h"
using namespace std;

TuringM::TuringM() {
    head = NULL;
    tail = NULL;
    current = NULL;
}

TuringM::TuringM(const TuringM& orig) {
}

TuringM::~TuringM() {
}

void TuringM::addHead(Elem* e) {
    e->back = NULL;
    e->next = head;
    head->back = e;
    head = e;
}

void TuringM::addTail(Elem* e) {
    e->next = NULL;
    e->back = tail;
    tail->next = e;
    tail = e;
}

void TuringM::add(Elem* e) {
    this->addTail(e);
}

void TuringM::start() {
    obrada();
}

/*
 * Pravi novu instrukciju od podataka i dodaje je u listu instrukcija
 */
void TuringM::addInstruction(int ts, int tz, int ns, int nz, int r) {
    Instruction* tmpInstrustion = new Instruction(ts, tz, ns, nz, r);
    tmpInstrustion->next = first;
    first = tmpInstrustion;
}

/*
 * Nalazi sledecu instrukciju na osnovu trenutnog stanja i trenutnog znaka
 */
TuringM::Instruction* TuringM::findInstruction(int ts, int tz) {
    TuringM::Instruction* pom = first;

    while (pom != NULL) {
        if ((pom->trenutnoStanje == ts) && (pom->trenutniZnak == tz)) return pom;
        else pom = pom->next;
    }
    return NULL;
}

/*
 * Vrsi obradu instrukcija pomeranjem glave turingove masine levo i desno po traci
 * i menjajuci prednosti na tim pozicijama
 */
int TuringM::obrada() {
    int sledeceStanje = 0;

    while ((sledeceStanje != -1) && (sledeceStanje != -2)) {
        this->tmp = findInstruction(sledeceStanje, current->val);
        sledeceStanje = tmp->novoStanje;
        current->val = tmp->noviZnak;

        //ako se glava pomera u desno, proverava se da li je kraj zapisa
        //i ako jeste ns kraj se dodaje novi elemenat(b) niza
        //analogno i za pomeranje u levo dodaje se elemenat na pocetak
        if (tmp->pravac == 1) {
            if (current == tail) addTail(new Elem(-1));
            current = current->next;
        } else if (tmp->pravac == -1) {
            if (current == head) addHead(new Elem(-1));
            current = current->back;
        }
    }

    return sledeceStanje + 1; //vraca 0 za uspeh, -1 za neuspeh
}

void TuringM::ucitavanje() {
    //citanje podataka sa trake
    FILE * f_strap;

    f_strap = fopen("strap.txt", "r+");
    while (!feof(f_strap)) {
        char* word;
        fscanf(f_strap, "%c", word);
        if (*word != 'b') add(new Elem(atoi(word)));
        else add(new Elem(-1));
    }
    fclose(f_strap);


    //citanje instrukcija
    string instr;
    FILE * f_instructions;

    f_instructions = fopen("instructions.txt", "r+");
    while (!feof(f_instructions)) {
        char ts[5], tz[5], ns[5], nz[5], r[5];
        fscanf(f_instructions, "(%[^,],%[^)])->(%[^,],%[^,],%[^)])\n", &ts, &tz, &ns, &nz, &r);

        int itz, inz;

        if (atoi(tz) == 1) itz = 1;
        else if (atoi(tz) == 0) itz = 0;
        else itz = -1;
        if (atoi(nz) == 1) inz = 1;
        else if (atoi(nz) == 0) inz = 0;
        else inz = -1;

        addInstruction(atoi(ts), itz, atoi(ns), inz, atoi(r));
    }
    fclose(f_instructions);
}

void TuringM::printStrap() {
    Elem * priv = head;
    while (priv) {
        cout << "|b|";
        if (priv->val == -1) cout << "b|";
        else cout << priv->val << "|";
        priv = priv->next;
    }
    cout << "b|";
}
